from typing import Dict, List, Optional
from datetime import datetime
from decimal import Decimal
import pandas as pd
import logging
import numpy as np

from .event import Event, MarketEvent, SignalEvent, OrderEvent, FillEvent
from .data import DataHandler
from strategies.trading_strategy import TradingStrategy
from risk.risk_manager import RiskManager

logger = logging.getLogger(__name__)

class BacktestEngine:
    """回测引擎"""
    
    def __init__(
        self,
        data_handler: DataHandler,
        strategy: TradingStrategy,
        risk_manager: RiskManager,
        initial_capital: float = 100000.0
    ):
        """
        初始化回测引擎
        
        Args:
            data_handler: 数据处理器实例
            strategy: 交易策略实例
            risk_manager: 风险管理器实例
            initial_capital: 初始资金
        """
        self.data_handler = data_handler
        self.strategy = strategy
        self.risk_manager = risk_manager
        self.initial_capital = float(initial_capital)
        
        # 初始化投资组合状态
        self.current_positions = self._init_positions()
        self.current_holdings = self._init_holdings()
        
        # 历史记录
        self.all_positions = []
        self.all_holdings = []
        self.trade_history = []
        
        # 事件队列
        self.events = []
        
        print(f"\n初始化回测引擎...")
        print(f"初始资金: ${initial_capital:,.2f}")
    
    def _init_positions(self) -> Dict:
        """
        初始化持仓状态
        """
        positions = {}
        for symbol in self.data_handler.symbols:
            positions[symbol] = 0
        return positions
    
    def _init_holdings(self) -> Dict:
        """
        初始化资金状态
        """
        holdings = {
            'cash': self.initial_capital,
            'total': self.initial_capital,
            'commission': 0.0
        }
        for symbol in self.data_handler.symbols:
            holdings[symbol] = 0.0
        return holdings
    
    def _update_positions(self, fill_event: FillEvent):
        """
        更新持仓状态
        """
        direction = 1 if fill_event.direction == 'BUY' else -1
        self.current_positions[fill_event.symbol] += direction * fill_event.quantity
    
    def _update_holdings(self, fill_event: FillEvent):
        """
        更新资金状态
        """
        direction = 1 if fill_event.direction == 'BUY' else -1
        cost = direction * fill_event.quantity * fill_event.price
        commission = fill_event.commission
        
        # 更新现金和持仓市值
        self.current_holdings['cash'] -= (cost + commission)
        self.current_holdings[fill_event.symbol] = (
            self.current_positions[fill_event.symbol] * fill_event.price
        )
        self.current_holdings['commission'] += commission
        
        # 更新总资产
        self.current_holdings['total'] = (
            self.current_holdings['cash'] + 
            sum(self.current_holdings[s] for s in self.data_handler.symbols)
        )
        
        # 记录交易
        self.trade_history.append({
            'timestamp': fill_event.timestamp,
            'symbol': fill_event.symbol,
            'direction': fill_event.direction,
            'quantity': fill_event.quantity,
            'price': fill_event.price,
            'commission': fill_event.commission,
            'total': self.current_holdings['total']
        })
        
    def _execute_order(self, order_event: OrderEvent) -> Optional[FillEvent]:
        """
        执行订单
        
        Args:
            order_event: 订单事件
            
        Returns:
            成交事件
        """
        # 获取最新价格
        latest_bar = self.data_handler.get_latest_bar(order_event.exchange, order_event.symbol)
        if not latest_bar:
            return None
            
        # 使用收盘价作为成交价
        fill_price = latest_bar['close']
        
        # 创建成交事件
        fill_event = FillEvent(
            timestamp=order_event.timestamp,
            type='FILL',
            exchange=order_event.exchange,
            symbol=order_event.symbol,
            order_type=order_event.order_type,
            side=order_event.side,
            amount=order_event.amount,
            price=fill_price,
            commission=self.data_handler.commission,
            leverage=order_event.leverage
        )
        
        return fill_event
        
    def run_backtest(self):
        """
        运行回测
        """
        print("Running backtest...")
        print("开始回测...")
        
        try:
            while True:
                # 更新市场数据
                if not self.data_handler.continue_backtest:
                    break
                
                self.data_handler.update_bars()
                
                # 生成市场事件
                latest_bar = self.data_handler.get_latest_bar(self.data_handler.current_exchange, self.data_handler.current_symbol)
                market_event = MarketEvent(
                    timestamp=latest_bar['timestamp'],
                    type='MARKET',
                    exchange=self.data_handler.current_exchange,
                    symbol=self.data_handler.current_symbol,
                    data=latest_bar
                )
                self.events.append(market_event)
                
                # 处理所有事件
                while len(self.events) > 0:
                    event = self.events.pop(0)
                    
                    if event.type == 'MARKET':
                        self.strategy.calculate_signals(event)
                    elif event.type == 'SIGNAL':
                        self._process_signal_event(event)
                    elif event.type == 'ORDER':
                        self._process_order_event(event)
                    elif event.type == 'FILL':
                        self._process_fill_event(event)
                
                # 更新投资组合
                self._update_timeindex()
                
        except Exception as e:
            print(f"Backtest error: {str(e)}")
            raise
            
        finally:
            # 显示回测结果
            self._show_backtest_results()
            
    def _show_backtest_results(self):
        """显示回测结果"""
        if not self.all_holdings:
            print("没有交易记录")
            return
            
        initial_equity = self.initial_capital
        final_equity = self.all_holdings[-1]['total']
        
        # 计算收益率
        total_return = (final_equity - initial_equity) / initial_equity * 100
        
        # 计算最大回撤
        equity_curve = pd.DataFrame(self.all_holdings)
        equity_curve['return'] = equity_curve['total'].pct_change()
        equity_curve['equity_peak'] = equity_curve['total'].expanding(min_periods=1).max()
        equity_curve['drawdown'] = (equity_curve['total'] - equity_curve['equity_peak']) / equity_curve['equity_peak']
        max_drawdown = equity_curve['drawdown'].min() * 100
        
        # 计算交易统计
        trades = pd.DataFrame(self.trade_history)
        if not trades.empty:
            winning_trades = trades[trades['pnl'] > 0]
            losing_trades = trades[trades['pnl'] < 0]
            win_rate = len(winning_trades) / len(trades) * 100 if len(trades) > 0 else 0
            
            # 计算平均收益和损失
            avg_win = winning_trades['pnl'].mean() if not winning_trades.empty else 0
            avg_loss = losing_trades['pnl'].mean() if not losing_trades.empty else 0
            
            print("\n=== 回测结果 ===")
            print(f"初始资金: ${initial_equity:,.2f}")
            print(f"最终资金: ${final_equity:,.2f}")
            print(f"总收益率: {total_return:.2f}%")
            print(f"最大回撤: {abs(max_drawdown):.2f}%")
            print(f"总交易次数: {len(trades)}")
            print(f"胜率: {win_rate:.2f}%")
            print(f"平均盈利: ${avg_win:,.2f}")
            print(f"平均损失: ${avg_loss:,.2f}")
            print(f"手续费总额: ${self.all_holdings[-1]['commission']:,.2f}")
            
            # 显示每笔交易的详细信息
            print("\n最近5笔交易:")
            for trade in trades.tail().itertuples():
                print(f"交易 {trade.Index + 1}:")
                print(f"  时间: {trade.timestamp}")
                print(f"  方向: {trade.direction}")
                print(f"  价格: ${float(trade.price):,.2f}")
                print(f"  数量: {float(trade.quantity):,.4f}")
                print(f"  盈亏: ${float(trade.pnl):,.2f}")
                
            # 生成图表分析
            from utils.visualization import plot_trading_results, plot_trade_analysis
            
            # 保存交易结果图表
            plot_trading_results(
                equity_curve=equity_curve,
                trades=trades,
                save_path='trading_results.png'
            )
            print("\n交易结果图表已保存到 trading_results.png")
            
            # 保存交易分析图表
            plot_trade_analysis(
                trades=trades,
                save_path='trade_analysis.png'
            )
            print("交易分析图表已保存到 trade_analysis.png")
            
        else:
            print("\n=== 回测结果 ===")
            print("没有执行任何交易")
            print(f"初始资金: ${initial_equity:,.2f}")
            print(f"最终资金: ${final_equity:,.2f}")
            
    def get_backtest_results(self) -> Dict:
        """
        计算并返回回测结果
        
        Returns:
            包含回测结果的字典
        """
        try:
            # 计算收益率序列
            returns = pd.Series([h['total'] for h in self.all_holdings])
            
            # 计算累计收益率
            total_returns = ((self.current_holdings['total'] / self.initial_capital) - 1) * 100
            
            # 计算夏普比率 (假设无风险利率为0)
            daily_returns = returns.pct_change()
            sharpe_ratio = np.sqrt(252) * (daily_returns.mean() / daily_returns.std())
            
            # 计算最大回撤
            cumulative_returns = (1 + returns.pct_change()).cumprod()
            rolling_max = cumulative_returns.expanding().max()
            drawdowns = (cumulative_returns - rolling_max) / rolling_max
            max_drawdown = abs(drawdowns.min()) * 100
            
            # 计算交易统计
            trades = []
            for i in range(1, len(self.all_holdings)):
                if self.all_holdings[i]['total'] != self.all_holdings[i-1]['total']:
                    trades.append({
                        'pnl': self.all_holdings[i]['total'] - self.all_holdings[i-1]['total'],
                        'side': 'long' if self.all_holdings[i]['total'] > self.all_holdings[i-1]['total'] else 'short'
                    })
            total_trades = len(trades)
            winning_trades = len([t for t in trades if t['pnl'] > 0])
            win_rate = (winning_trades / total_trades * 100) if total_trades > 0 else 0
            
            # 计算平均每笔收益
            if total_trades > 0:
                avg_trade_return = sum(t['pnl'] for t in trades) / total_trades
            else:
                avg_trade_return = 0
            
            # 计算收益风险比
            if max_drawdown > 0:
                profit_risk_ratio = total_returns / max_drawdown
            else:
                profit_risk_ratio = 0
            
            results = {
                'total_returns': float(total_returns),
                'sharpe_ratio': float(sharpe_ratio),
                'max_drawdown': float(max_drawdown),
                'win_rate': float(win_rate),
                'total_trades': total_trades,
                'avg_trade_return': float(avg_trade_return),
                'profit_risk_ratio': float(profit_risk_ratio),
                'final_balance': float(self.current_holdings['total']),
                'trade_history': self.trade_history,
                'returns_series': returns.tolist()
            }
            
            print("\n回测完成!")
            return results
            
        except Exception as e:
            print(f"计算回测结果时出错: {str(e)}")
            raise
